package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.heima.article.dtos.ApArticleDto;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.exception.CustomException;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.feign.article.ArticleFeignClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.pojos.WmChannel;
import com.heima.wemedia.pojos.WmNews;
import com.heima.wemedia.pojos.WmSensitive;
import com.heima.wemedia.pojos.WmUser;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private GreenImageScan greenImageScan;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private ArticleFeignClient articleFeignClient;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private WmUserService wmUserService;

    @Autowired
    private Tess4jClient tess4jClient;

    /**
     * 自动审核
     *
     * @param id 自媒体文章id
     */
    @Override
    @Async//异步调用
    public void autoScanWmNews(Integer id) {
        //存放文本 和 图片
        StringBuilder allTexts = new StringBuilder();
        ArrayList<String> allImages = new ArrayList<>();

        /**
         * 参数校验
         */
        //id是否存在
        if (id == null) {
            return;
        }
        //自媒体文章是否存在
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews == null) {
            return;
        }

        //存放-自媒体文章图片
        if (wmNews.getImages() != null) {
            allImages.addAll(Arrays.asList(wmNews.getImages().split(",")));
        }
        //存放-自媒体文章内容文字
        allTexts.append(wmNews.getTitle()).append("-");

        /**
         * 解析json,提取自媒体文章中的文本 与 图片
         */
        getWemediaContentAllTextAndImage(allTexts, allImages, wmNews);

        /**
         * 新增需求: 自管理敏感词
         */
        Boolean sensitivesScanRS = sensitivesScan(allTexts, wmNews);
        if (!sensitivesScanRS) {
            //扫描出敏感词直接结束
            return;
        }

        /**
         *  自媒体文章内容文字-自动审核
         */
//         boolean textRS = scanText(wmNews, allTexts.toString());//测试自媒体发布不通过,修改自媒文章为待人工审核
        boolean textRS = true;//测试文本内容审核通过
        //文本审核失败 直接结束
        if (!textRS) {
            return;
        }

        /**
         * 自媒体文章图片-自动审核
         */
//        boolean imageRS = scanImage(wmNews, allImages);//测试自媒体发布不通过,修改自媒文章为待人工审核
        boolean imageRS = true;//测试图片审核通过
        //图片审核失败 直接结束
        if (!imageRS) {
            return;
        }

        /**
         * 审核通过 保存至app相关文章
         */
        saveApArticle(wmNews);
    }

    /**
     * 解析json,提取自媒体文章中的文本 与 图片
     *
     * @param allTexts  解析json后存放的    自媒体文章内容文字
     * @param allImages 解析json后存放的    自媒体文章图片
     * @param wmNews    Wemedia自媒体文章
     */
    private void getWemediaContentAllTextAndImage(StringBuilder allTexts, ArrayList<String> allImages, WmNews wmNews) {
        String content = wmNews.getContent();
        JSONArray contentsJson = JSON.parseArray(content);
        //获取json集合中的每一个json对象
        for (int i = 0; i < contentsJson.size(); i++) {
            JSONObject jsonObject = contentsJson.getJSONObject(i);
            //每一个json中的数据
            String type = jsonObject.getString("type");//类型
            String value = jsonObject.getString("value");//内容
            //将文章中的内容 图片 添加到集合中
            if (type.equals("text")) {
                allTexts.append(value);
            } else {
                allImages.add(value);
            }
        }
    }

    /**
     * 保存自媒体文章至文章微服务
     *
     * @param wmNews 自媒体文章
     */
    private void saveApArticle(WmNews wmNews) {
        ApArticleDto apArticleDto = new ApArticleDto();
        //封装articleDto数据
        apArticleDto.setTitle(wmNews.getTitle());//标题
        apArticleDto.setAuthorId(wmNews.getUserId());//作者id
        LambdaQueryWrapper<WmUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(WmUser::getId, wmNews.getUserId());
        WmUser wmUser = wmUserService.getOne(wrapper);
        apArticleDto.setAuthorName(wmUser.getName());//作者昵称
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        apArticleDto.setChannelId(wmChannel.getId());//频道id
        apArticleDto.setChannelName(wmChannel.getName());//频道名称
        apArticleDto.setLayout(wmNews.getType());//文章布局
        apArticleDto.setImages(wmNews.getImages());//图片
        apArticleDto.setLabels(wmNews.getLabels());//标签
        apArticleDto.setCreatedTime(wmNews.getCreatedTime());
        apArticleDto.setPublishTime(wmNews.getPublishTime());
        apArticleDto.setContent(wmNews.getContent());//文章内容

        //保存自媒体文章至文章微服务
        ResponseResult<Long> result = articleFeignClient.save(apArticleDto);
        int code = result.getCode();
        if (code == AppHttpCodeEnum.SUCCESS.getCode()) {
            wmNews.setArticleId(result.getData());//文章id
            wmNews.setStatus(Integer.valueOf(WmNews.Status.PUBLISHED.getCode() + ""));//已发布
            wmNewsMapper.updateById(wmNews);
        } else {
            throw new CustomException(AppHttpCodeEnum.SERVER_ERROR);
        }
    }

    /**
     * 过滤 自管理敏感词
     *
     * @param allTexts 识别的文字内容
     * @param wmNews   自媒体文章对象,用来修改文章的审核结果
     * @return ture    未识别出敏感词汇 false识别出敏感词汇
     */
    private Boolean sensitivesScan(StringBuilder allTexts, WmNews wmNews) {
        boolean rs = true;

        //select sensitives from wm_sensitive
        //查询条件 在敏感词库中查询不为null的记录
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(null);
        //过滤出所有 敏感词汇
        List<String> sensitivesList = wmSensitives
                .stream()
                .map(wmSensitive -> wmSensitive.getSensitives()).
                collect(Collectors.toList());
        //初始化敏感词库
        SensitiveWordUtil.initMap(sensitivesList);
        //查询文章内容文字中的敏感词
        Map<String, Integer> map = SensitiveWordUtil.matchWords(allTexts.toString());
        //如果有敏感词 修改审核未通过原因
        if (map.size() != 0) {
            newsExamineResult(wmNews, WmNews.Status.FAIL.getCode(), "文章中包含敏感词:" + map);
            rs = false;
        }

        return rs;
    }

    /**
     * 审核文本
     *
     * @param wmNews  自媒体文章
     * @param content 自媒体文章中文字内容
     * @return 审核结果 true通过 false审核未通过
     */
    private boolean scanText(WmNews wmNews, String content) {
        boolean rs = true;

        try {
            Map map = greenTextScan.greeTextScan(content);//调用接口审核文本
            //如果为null审核失败
            if (map == null) {
                newsExamineResult(wmNews, WmNews.Status.FAIL.getCode(), "文章审核未通过");
                rs = false;
            } else {
                //如果不为空 校验审核是否通过
                String suggestion = map.get("suggestion").toString();
                //人工审核
                if ("review".equals(suggestion)) {
                    newsExamineResult(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "等待人工审核");
                    rs = false;
                } else if ("block".equals(suggestion)) {
                    //内容违规
                    newsExamineResult(wmNews, WmNews.Status.FAIL.getCode(), "文章包含违规内容,审核失败");
                    rs = false;
                }
                //审核通过
            }
        } catch (Exception e) {
            newsExamineResult(wmNews, WmNews.Status.FAIL.getCode(), "文章审核未通过");
            rs = false;
            e.printStackTrace();
        }

        return rs;
    }

    /**
     * 审核图片
     *
     * @param wmNews    自媒体文章
     * @param allImages 所有图片
     * @return 审核结果 true审核通过 false审核不通过
     */
    private boolean scanImage(WmNews wmNews, List<String> allImages) {
        boolean rs = true;
        try {
            List<byte[]> imageBytes = new ArrayList<>();
            //下载图片
            for (String image : allImages) {
                byte[] imageByte = fileStorageService.downLoadFile(image);
                imageBytes.add(imageByte);
                /**
                 * 新增需求:图片文字识别
                 */
                BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageByte));
                String imageText = tess4jClient.doOCR(bufferedImage);
                //审核图片-文字内容
                Boolean imageScan = sensitivesScan(new StringBuilder(imageText), wmNews);
                //图片审核中有违规内容,直接结束,不调用阿里的审核接口
                if (!imageScan) {
                    rs = false;
                    return rs;
                }

            }
            // 将下载的图片存放到字节数组中
            Map map = greenImageScan.imageScan(imageBytes);//调用接口审核图片
            //如果为null审核失败
            if (map == null) {
                newsExamineResult(wmNews, WmNews.Status.FAIL.getCode(), "图片审核未通过");
                rs = false;
            } else {
                //如果不为空 校验审核是否通过
                String suggestion = map.get("suggestion").toString();
                //人工审核
                if ("review".equals(suggestion)) {
                    newsExamineResult(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "等待人工审核");
                    rs = false;
                } else if ("block".equals(suggestion)) {
                    //审核不通过
                    newsExamineResult(wmNews, WmNews.Status.FAIL.getCode(), "图片包含违规内容,审核失败");
                    rs = false;
                }
            }
        } catch (Exception e) {
            newsExamineResult(wmNews, WmNews.Status.FAIL.getCode(), "审核失败");
            rs = false;
            e.printStackTrace();
        }

        return rs;
    }

    /**
     * 修改审核状态
     *
     * @param wmNews 修改的文章
     * @param status 修改状态
     * @param reason 审核不通过原因
     */
    private void newsExamineResult(WmNews wmNews, short status, String reason) {
        wmNews.setStatus(Integer.valueOf(status + ""));
        wmNews.setReason(reason);
        //修改文章
        wmNewsMapper.updateById(wmNews);
    }
}
